/* 
	Copyright 2011 David Young. All Rights Reserved. I love you and your poorly commented code unreal <3.
*/

//8 <- Number of classes I had to scan through in order to know what the fuck is going on in this shit.

class RDWeapon extends UTWeapon
	abstract;

//------------------------------Clip system variables

//Defaults for organization.
const DefMaxClipCount = 10;
const DefMaxClipSize = 30;
const DefClipCount = 3;

//Modifiable vars.
var int MaxClipCount;
var int ClipCount;

//Used in tandem with ammo count.
var int MaxClipSize;

//Automatically reload the gun?
var bool bAutoReload;

//Is this going currently in the reloading state?
var bool bIsReloading;

//-------------------------------Misc.
//Force the player to switch weapons when this gun has no MOAR ammo?
var bool bForceWeaponSwitch;

//Did we already release the firing hammer?
var bool bAlreadyPlayedEmptySound;

//How long do we want the reload to last?
var float bReloadTime;

//========================================================================================================
//OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOH! Networrkkkinnnngg    :O. Needed this cuz mah stuff wasn't working.
//========================================================================================================

//Variables to replicate?
replication
{
	// Server->Client properties
	if ( bNetOwner )
		ClipCount;
}

//This is called when the client & server sync.
simulated event ReplicatedEvent(name VarName)
{
	if ( VarName == 'AmmoCount' )
	{
		if ( !HasAnyAmmo() )
		{
			WeaponEmpty();
		}
	}
	else if ( VarName == 'HitEnemy' )
	{
		LastHitEnemyTime = WorldInfo.TimeSeconds;
	}
	else
	{
		Super(UDKWeapon).ReplicatedEvent(VarName);
	}
}

//Reload.
exec function GBA_ExecReload()
{
	HandleReloadRequest();
}

//Handles the reload and preforms a check to make sure reloading won't break the gun.
function HandleReloadRequest()
{
	if(!bIsReloading && !isFiring())
		GotoState('Reloading');
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////// FUNCTIONS ( ,o *O* )=D  <( ;__; <)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Ammo Functionality - Mostly overides and interjections.

//Adds ammo based on an amount and does a quick check to see if the clip count is maxed. Ammo is picked up in clips.
function int AddAmmo( int Amount )
{
	AmmoCount = Clamp(AmmoCount + Amount,0,MaxClipSize);
	
	// check for infinite ammo
	if ( (UTInventoryManager(InvManager) == None || UTInventoryManager(InvManager).bInfiniteAmmo) )
	{
		ClipCount = MaxClipCount;
		AmmoCount = MaxClipSize;
	}

	return Amount;
}

//Adds ammunition based on a clamp.
function int AddClip( int Amount )
{
	if( Amount + ClipCount > MaxClipCount )
	{
		ClipCount = MaxClipCount;
		Amount = (Amount + ClipCount) - MaxClipCount;
	}
	else
	{
		ClipCount = ClipCount + Amount;
		Amount = 0;
	}
	
	// check for infinite ammo
	if ( (UTInventoryManager(InvManager) == None || UTInventoryManager(InvManager).bInfiniteAmmo) )
	{
		ClipCount = MaxClipCount;
		AmmoCount = MaxClipSize;
	}
	
	return Amount;
}

//Checks to see if you have the max amount of clips.
simulated function bool AmmoMaxed(int mode)
{
	return (ClipCount >= MaxClipCount);
}

//Gets the desired ammo count.
simulated function int GetAmmoCount()
{
	return AmmoCount;
}

//Used in determining the desireability of the weapon for AI.
simulated function float DesireAmmo(bool bDetour)
{
	return (1.f - float(AmmoCount)/MaxClipSize);
}

//Self Explanitory
simulated function bool NeedAmmo()
{
	return ( ClipCount < Default.ClipCount );
}

//Occurs after the weapon is loaded in order to set it's initial ammo.
simulated function Loaded(optional bool bUseWeaponMax)
{
	if (bUseWeaponMax)
	{
		ClipCount = MaxClipCount;
	}
	else
		ClipCount = DefClipCount;
	
	AmmoCount = MaxClipSize;
}

//Used to call the weapon empty function based on current ammo status.
simulated function bool HasAmmo( byte FireModeNum, optional int Amount )
{
	if (Amount==0)
		return ( AmmoCount >= ShotCost[FireModeNum]);
	else
		return ( AmmoCount >= Amount );
}

//Does this gun canhaz ammo?
simulated function bool HasAnyAmmo()
{
	return ( ( AmmoCount > 0 || ClipCount > 0 ) || (ShotCost[0]==0 && ShotCost[1]==0) );
}

//Play reload sound.
simulated function PlayReloadSound()
{
	bAlreadyPlayedEmptySound = true;

}

//This is called when the clip is empty. Overidden.
simulated function WeaponEmpty()
{
	if( !bAlreadyPlayedEmptySound)
		PlayReloadSound();
	if( bAutoReload )
	{
		GotoState('Reloading');
		return;
	}
	
	if ( IsFiring() )
	{
		GotoState('Active');
	}
	
	if ( Instigator != none && Instigator.IsLocallyControlled() && bForceWeaponSwitch)
	{
		Instigator.InvManager.SwitchToBestWeapon( true );
	}
	
	return;
}

//Doth thou only want thy ammos?

function bool DenyPickupQuery(class<Inventory> ItemClass, Actor Pickup)
{
	local DroppedPickup DP;

	// By default, you can only carry a single item of a given class.
	if ( ItemClass == class )
	{
		DP = DroppedPickup(Pickup);
		if (DP != None)
		{
			if ( DP.Instigator == Instigator )
			{
				// weapon was dropped by this player - disallow pickup
				return true;
			}
			
			// take the ammo that the dropped weapon has
			if ( RDWeapon(DP.Inventory).AmmoCount >= MaxClipSize )
			{
				RDWeapon(DP.Inventory).ClipCount = AddClip(RDWeapon(DP.Inventory).ClipCount + 1);
				RDWeapon(DP.Inventory).AmmoCount = 0;
			}
			else
				RDWeapon(DP.Inventory).ClipCount = AddClip(RDWeapon(DP.Inventory).ClipCount);
				
			DP.PickedUpBy(Instigator);
			AnnouncePickup(Instigator);
		}
		else
		{
			// add the ammo that the pickup should give us, then tell it to respawn
			if ( default.AmmoCount >= MaxClipSize )
			{
				AddClip(default.ClipCount + 1);
			}
			else
				AddClip(default.ClipCount);
				
			if ( PickupFactory(Pickup) != None )
			{
				PickupFactory(Pickup).PickedUpBy(Instigator);
			}
			AnnouncePickup(Instigator);
		}
		return true;
	}

	return false;
}

//AI thinks this wep0n is sexy?
static function float BotDesireability(Actor PickupHolder, Pawn P, Controller C)
{
	local RDWeapon AlreadyHas;
	local float desire;
	local UTBot Bot;

	Bot = UTBot(C);
	if ( Bot == None )
		return 0;

	if ( UTWeaponLocker(PickupHolder) != None )
		return UTWeaponLocker(PickupHolder).BotDesireability(P, C);

	// bots adjust their desire for their favorite weapons
	desire = Default.MaxDesireability;
	if (ClassIsChildOf(default.Class, Bot.FavoriteWeapon))
	{
		desire *= 1.5;
	}

	// see if bot already has a weapon of this type
	AlreadyHas = RDWeapon(P.FindInventoryType(default.class));
	if ( AlreadyHas != None )
	{
		if ( Bot.bHuntPlayer )
			return 0;

		// can't pick it up if weapon stay is on
		if ( (UTWeaponPickupFactory(PickupHolder) != None) && !UTWeaponPickupFactory(PickupHolder).AllowPickup(Bot) )
			return 0;

		if ( AlreadyHas.AmmoMaxed(0) )
			return 0.25 * desire;

		// bot wants this weapon for the ammo it holds
		if( AlreadyHas.ClipCount > 0 || AlreadyHas.AmmoCount >= AlreadyHas.MaxClipSize )
		{
			if ( Default.AmmoPickupClass == None )
				return 0.05;
			else
				return FMax( 0.25 * desire,
						Default.AmmoPickupClass.Default.MaxDesireability
						* FMin(1, 0.15 * AlreadyHas.MaxClipSize/AlreadyHas.AmmoCount) );
		}
		else
			return 0.05;
	}
	if ( Bot.bHuntPlayer && (desire * 0.833 < P.Weapon.AIRating - 0.1) )
		return 0;

	// incentivize bot to get this weapon if it doesn't have a good weapon already
	if ( (P.Weapon == None) || (P.Weapon.AIRating < 0.5) )
		return 2*desire;

	return desire;
}

//--------------------------------------------------------------==============================
//Stubs
//--------------------------------------------------------------==============================
simulated function DoReloadAnimation(optional byte animNum)
{
	return;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////// STTAAYYUUTTSSSSS  [you mean like Virginia?]     <- Kill this fool.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Talking to myself is fun.

//Overide some state functionality. Fuck you unreal :X.
simulated state WeaponFiring
{
	//See the global version for explanation.
	simulated event ReplicatedEvent(name VarName)
	{
		if ( VarName == 'AmmoCount' && !HasAnyAmmo() )
		{
			return;
		}

		Global.ReplicatedEvent(VarName);
	}
}

//Reload the weapon.
simulated state Reloading
{
	//Does a quick check to make sure this gun has ammo.
	simulated event BeginState( Name PreviousStateName )
	{
		//We don't want to start firing while reloading.
		bIsReloading = true;
		
		if( ClipCount > 0 && AmmoCount < MaxClipSize && !IsFiring() )
		{
			PreReload();
			ReloadWeapon();
		}
		else
			//Return to active state.
			GotoState('Active');
	}
	
	//Unset bIsReloading to let the pawn know that we are good to fire.
	simulated event EndState( Name NextStateName )
	{
		bIsReloading = false;
		`Log("Exiting reload...");
	}
	
	function PreReload()
	{	
		bAlreadyPlayedEmptySound = false;
	}
	
	function PostReload()
	{
		ClipCount = ClipCount - 1;
		AmmoCount = MaxClipSize;
	}
	
	//Wait for a bit to allow anims time to run.
	simulated function Wait()
	{
		`Log("Entering Wait...");
		PostReload();
		GotoState('Active');
	}
	
	//Stub
	simulated function PlayReloadAnims()
	{
	
	}
	
	//Starts the animation execution and waits for it to finish.
	simulated function ReloadWeapon()
	{
		`Log("Reloading...");
		PlayReloadAnims();
		SetTimer(bReloadTime, false, 'Wait');
	}
}


defaultproperties 
{
	//-========================================-
	//My stuff
	//-========================================-
	
	//---------Ammo Variables
	bAutoReload= false
	bForceWeaponSwitch= false
	
	bIsReloading= false
	bReloadTime= 2.0
	
	MaxClipCount= DefMaxClipCount
	MaxClipSize= DefMaxClipSize
	ClipCount= 3
	
	//Not mine, but I need to set these to the correct values. Plus, I don't feel like scrolling down.
	LockerAmmoCount=30
	ShotCost(0)=1
	ShotCost(1)=1
	AmmoCount=DefMaxClipSize
	MaxAmmoCount=DefMaxClipSize
	
	
	
	
	//-========================================-
	//UTWeapon stuff
	//-========================================-
	//---------Projectiles and firing.
	WeaponFireTypes(0)=EWFT_InstantHit
	WeaponFireTypes(1)=EWFT_Projectile
	
	InstantHitDamage(0)=45
	FireInterval(0)=+0.15
	FireInterval(1)=+0.6
	
	WeaponProjectiles(1)=class'RDProj_Ballistic'
	InstantHitDamageTypes(0)=class'UTDmgType_ShockPrimary'
	InstantHitDamageTypes(1)=None
	InstantHitMomentum(0)=+60000.0
	
	//----------Sounds
	WeaponFireSnd[0]=SoundCue'WP_RD_ALL.Sounds.generic_shot_close_Cue'
	WeaponFireSnd[1]=SoundCue'WP_RD_ALL.Sounds.generic_shot_close_Cue'
	WeaponEquipSnd=SoundCue'A_Weapon_ShockRifle.Cue.A_Weapon_SR_RaiseCue'
	WeaponPutDownSnd=SoundCue'A_Weapon_ShockRifle.Cue.A_Weapon_SR_LowerCue'
	PickupSound=SoundCue'A_Pickups.Weapons.Cue.A_Pickup_Weapons_Shock_Cue'
	
	//---------Weapon SkeletalMesh
	Begin Object class=AnimNodeSequence Name=MeshSequenceA
	End Object
	
	Begin Object Name=FirstPersonMesh
		SkeletalMesh=SkeletalMesh'WP_AK47.Mesh.WP_AK47_1P'
		AnimSets(0)=AnimSet'WP_ShockRifle.Anim.K_WP_ShockRifle_1P_Base'
		Animations=MeshSequenceA
		Rotation=(Yaw=-16384)
		FOV=60.0
	End Object
	
	Begin Object Name=PickupMesh
		SkeletalMesh=SkeletalMesh'WP_AK47.Mesh.WP_AK47_1P'
	End Object
	
	FireOffset=(X=20,Y=5)
	PlayerViewOffset=(X=17,Y=10.0,Z=-8.0)
	
	//---------Misc.
	AttachmentClass=class'RebelDawn.RDAttachment_Default'
	
	Begin Object Class=ForceFeedbackWaveform Name=ForceFeedbackWaveformShooting1
		Samples(0)=(LeftAmplitude=30,RightAmplitude=20,LeftFunction=WF_Constant,RightFunction=WF_Constant,Duration=0.100)
	End Object
	WeaponFireWaveForm=ForceFeedbackWaveformShooting1
	
	//--------AI variables
	MaxDesireability=0.65
	AIRating=0.65
	CurrentRating=0.65
	bInstantHit=true
	bSplashJump=false
	bRecommendSplashDamage=false
	bSniping=true
	ShouldFireOnRelease(0)=0
	ShouldFireOnRelease(1)=1

	
	
	//---------Animations
	FireCameraAnim(1)=CameraAnim'Camera_FX.ShockRifle.C_WP_ShockRifle_Alt_Fire_Shake'
	WeaponFireAnim(1)=WeaponAltFire
	
	//--------Muzzleflash and aiming.
	MuzzleFlashSocket=MF
	MuzzleFlashPSCTemplate=WP_AK47.Effects.griflemf
	MuzzleFlashAltPSCTemplate=WP_AK47.Effects.griflemf
	MuzzleFlashColor=(R=200,G=120,B=255,A=255)
	MuzzleFlashDuration=0.33
	MuzzleFlashLightClass=class'UTGame.UTShockMuzzleFlashLight'
	CrossHairCoordinates=(U=256,V=0,UL=64,VL=64)
	LockerRotation=(Pitch=32768,Roll=16384)
	
	//------------Icon
	IconCoordinates=(U=728,V=382,UL=162,VL=45)

	WeaponColor=(R=160,G=0,B=255,A=255)

	InventoryGroup=4
	GroupWeight=0.5

	IconX=400
	IconY=129
	IconWidth=22
	IconHeight=48

}